package com.karrysong.blog_springboot.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.karrysong.blog_springboot.entity.*;
import com.karrysong.blog_springboot.enums.ErrorCode;
import com.karrysong.blog_springboot.mapper.ArticleBodyMapper;
import com.karrysong.blog_springboot.mapper.ArticleMapper;
import com.karrysong.blog_springboot.mapper.ArticleTagMapper;
import com.karrysong.blog_springboot.service.ArticleService;
import com.karrysong.blog_springboot.service.CategoryService;
import com.karrysong.blog_springboot.service.TagService;
import com.karrysong.blog_springboot.service.UserService;
import com.karrysong.blog_springboot.util.UserThreadLocal;
import com.karrysong.blog_springboot.vo.*;
import com.karrysong.blog_springboot.vo.params.ArticleMessage;
import com.karrysong.blog_springboot.vo.params.ArticlePage;
import com.karrysong.blog_springboot.vo.params.ArticleParam;
import com.karrysong.blog_springboot.vo.params.PageParams;
import org.apache.logging.log4j.util.Strings;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;

/**
 * @ClassName: ArticleServiceImpl
 * @Author: KarrySong
 * @Date: 2022/8/2 17:23
 * @Description:
 */
@Service
public class ArticleServiceImpl implements ArticleService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private ArticleBodyMapper articleBodyMapper;
    @Autowired
    private ArticleTagMapper articleTagMapper;
    @Autowired
    private TagService tagService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private UserService userService;

    @Override
    public List<ArticleVo> listArticlesPage(PageParams pageParams) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        Page<Article> page = new Page<>(pageParams.getPage(),pageParams.getPageSize());
        Page<Article> articlePage = articleMapper.selectPage(page, queryWrapper);
        List<ArticleVo> articleVoList = copyList(articlePage.getRecords(),true,false,true);
        return articleVoList;
    }

    @Override
    public Result hotArticle(int limit) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getViewCounts);
        queryWrapper.select(Article::getId,Article::getTitle);
        queryWrapper.eq(Article::getIsCloseView, 0);
        queryWrapper.last("limit " + limit);
        List<Article> articles = articleMapper.selectList(queryWrapper);

        System.out.println("hot");
        for (Article article : articles) {
            System.out.println(article);
        }

        return Result.success(copyList(articles,false,false, false));
    }

    @Override
    public Result newArticles(int limit) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getCreateDate);
        queryWrapper.select(Article::getId,Article::getTitle);
        queryWrapper.eq(Article::getIsCloseView, 0);
        queryWrapper.last("limit "+limit);
        //select id,title from article order by create_date desc limit 5
        List<Article> articles = articleMapper.selectList(queryWrapper);

        System.out.println("new");
        for (Article article : articles) {
            System.out.println(article);
        }

        return Result.success(copyList(articles, false, false, false));
    }

    @Override
    public Result listArchives() {
        List<Archives> archivesList = articleMapper.listArchives();
        return Result.success(archivesList);
    }

    @Override
    public Result findArticleById(Long id) {
        Article article = articleMapper.selectById(id);

        System.out.println(article);

        ArticleVo articleVo = copy(article, true, true, true);
        return Result.success(articleVo);
    }

    @Override
    public void addViewCounts(Long id) {
        Article article = articleMapper.selectById(id);
        article.setViewCounts(article.getViewCounts() + 1);
        articleMapper.updateById(article);
    }

    @Override
    public Result listArticle(ArticlePage articlePage) {

        Page<Article> page = new Page<>(articlePage.getPage(),articlePage.getPageSize());

        IPage<Article> articleIPage = articleMapper.listArticle(
                page,
                articlePage.getCategoryId(),
                articlePage.getTagId(),
                articlePage.getYear(),
                articlePage.getMonth());
        List<Article> records = articleIPage.getRecords();
        List<ArticleVo> articleVoList = copyList(records,true,false, true);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("articleList", articleVoList);
        jsonObject.put("pageData", articleIPage);
        return Result.success(jsonObject);
    }

    @Override
    public Result adminListArticle(ArticlePage articlePage) {
        Page<Article> page = new Page<>(articlePage.getPage(),articlePage.getPageSize());

        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();

        wrapper.like(Strings.isNotEmpty(articlePage.getTitle()), Article::getTitle, articlePage.getTitle());
        wrapper.eq(articlePage.getCategoryId() != null, Article::getCategoryId, articlePage.getCategoryId());
        wrapper.eq(articlePage.getAuthorId() != null, Article::getAuthorId, articlePage.getAuthorId());
        wrapper.ge(articlePage.getTimeStart() != null, Article::getCreateDate, articlePage.getTimeStart());
        wrapper.le(articlePage.getTimeEnd() != null, Article::getCreateDate, articlePage.getTimeEnd());

        IPage<Article> articlePageResult = articleMapper.selectPage(page, wrapper);
        List<Article> records = articlePageResult.getRecords();
        List<ArticleVo> articleVoList = copyList(records,true,false, true);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("articleList", articleVoList);
        jsonObject.put("pageData", articlePageResult);
        return Result.success(jsonObject);

    }

    @Override
    public Result changeArticleStatus(Long id, Integer newStatus) {
        Article article = new Article();
        article.setId(id);
        article.setIsCloseView(newStatus);
        int i = articleMapper.updateById(article);
        if (i > 0){
            return Result.success(null);
        }else {
            return Result.fail(ErrorCode.ADMIN_ERROR, "修改文章状态失败");
        }
    }

    @Override
    public Result deleteArticle(Long id) {
        int i = articleMapper.deleteById(id);
        if (i > 0){
            //删除文章内容
            LambdaQueryWrapper<ArticleBody> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ArticleBody::getArticleId, id);
            ArticleBody articleBody = articleBodyMapper.selectOne(wrapper);
            articleBodyMapper.deleteById(articleBody.getId());
            //删除文章标签
            LambdaQueryWrapper<ArticleTag> tagWrapper = new LambdaQueryWrapper<>();
            tagWrapper.eq(ArticleTag::getArticleId, id);
            articleTagMapper.delete(tagWrapper);
            /**
             * 此处还需删除评论
             */
            return Result.success(null);
        }else {
            return Result.fail(ErrorCode.ADMIN_ERROR, "删除文章失败");
        }
    }

    @Override
    public Result publish(ArticleParam articleParam) {
        //此接口 要加入到登录拦截当中
        User sysUser = UserThreadLocal.get();
        /**
         * 1. 发布文章 目的 构建Article对象
         * 2. 作者id  当前的登录用户
         * 3. 标签  要将标签加入到 关联列表当中
         * 4. body 内容存储 article bodyId
         */
        Article article = new Article();
        boolean isEdit = false;
        if (articleParam.getId() != null){
            //修改文章
            article.setId(articleParam.getId());
            article.setTitle(articleParam.getTitle());
            article.setSummary(articleParam.getSummary());
            article.setCategoryId(articleParam.getCategory().getId());
            article.setIsVipView(articleParam.getIsVipView());
            article.setIsOpenView(articleParam.getIsOpenView());
            article.setIsCloseView(articleParam.getIsCloseView());
            articleMapper.updateById(article);
            isEdit = true;
        }else{
            //新增文章
            article.setAuthorId(sysUser.getId());
            article.setWeight(Article.Article_Common);
            article.setViewCounts(0);
            article.setTitle(articleParam.getTitle());
            article.setSummary(articleParam.getSummary());
            article.setCommentCounts(0);
            article.setSupportCounts(0);
            article.setIsCloseView(0);
            article.setIsOpenView(1);
            article.setIsVipView(0);
            article.setCreateDate(System.currentTimeMillis());
            article.setCategoryId(articleParam.getCategory().getId());

            //先给一个空内容id
            article.setBodyId(-1L);
            //插入之后 会生成一个文章id
            this.articleMapper.insert(article);
        }
        //tag
        List<TagVo> tags = articleParam.getTags();
        System.out.println("tags.len:" +tags.size());
        if (tags != null){

            Long articleId = article.getId();
            //这个不移到外面只能插入最后一个tag，因为每次插入前都把别的删了
            if (isEdit){
                //先删除
                LambdaQueryWrapper<ArticleTag> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(ArticleTag::getArticleId,articleId);
                articleTagMapper.delete(queryWrapper);
            }

            for (TagVo tag : tags) {
                ArticleTag articleTag = new ArticleTag();
                articleTag.setTagId(tag.getId());
                articleTag.setArticleId(articleId);
                articleTagMapper.insert(articleTag);
            }
        }
        //body
        if (isEdit){
            ArticleBody articleBody = new ArticleBody();
            articleBody.setArticleId(article.getId());
            articleBody.setContent(articleParam.getBody().getContent());
            articleBody.setContentHtml(articleParam.getBody().getContentHtml());
            LambdaUpdateWrapper<ArticleBody> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.eq(ArticleBody::getArticleId,article.getId());
            articleBodyMapper.update(articleBody, updateWrapper);
        }else {
            ArticleBody articleBody = new ArticleBody();
            articleBody.setArticleId(article.getId());
            articleBody.setContent(articleParam.getBody().getContent());
            articleBody.setContentHtml(articleParam.getBody().getContentHtml());
            articleBodyMapper.insert(articleBody);

            article.setBodyId(articleBody.getId());
            articleMapper.updateById(article);
        }
        Map<String,String> map = new HashMap<>();
        map.put("id",article.getId().toString());

        if (isEdit){
            //发送一条消息给rocketmq 当前文章更新了，更新一下缓存吧
            ArticleMessage articleMessage = new ArticleMessage();
            articleMessage.setArticleId(article.getId());
//            rocketMQTemplate.convertAndSend("blog-update-article",articleMessage);
        }
        return Result.success(map);
    }

    @Override
    public Result searchArticleByName(String search) {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(Article::getTitle, search);
        //放宽条件，简介内有也行
        wrapper.or().like(Article::getSummary, search);
        //
        wrapper.orderByDesc(Article::getWeight);
        List<Article> articleList = articleMapper.selectList(wrapper);
        List<ArticleVo> articleVos = copyList(articleList, true, false, true);
        return Result.success(articleVos);
    }

    public ArticleVo copy(Article article, boolean isAuthor, boolean isBody, boolean isTags){
        ArticleVo articleVo = new ArticleVo();

        if (isBody){
            System.out.println(article);
            ArticleBody articleBody = articleBodyMapper.selectById(article.getBodyId());
            ArticleBodyVo articleBodyVo = new ArticleBodyVo();
            articleBodyVo.setContent(articleBody.getContentHtml());
            articleVo.setBody(articleBodyVo);
        }

        BeanUtils.copyProperties(article, articleVo);
        if (isAuthor) {
            User sysUser = userService.findUserById(article.getAuthorId());
            UserVo userVo = userService.copy(sysUser);
            articleVo.setAuthor(userVo);
        }
        articleVo.setCreateDate(new DateTime(article.getCreateDate()).toString("yyyy-MM-dd HH:mm:ss"));
        if (isTags){
            List<TagVo> tags = tagService.findTagsByArticleId(article.getId());
            articleVo.setTags(tags);
        }
        Long categoryId = article.getCategoryId();
        articleVo.setCategoryVo(categoryService.findCategoryById(categoryId));
        return articleVo;
    }

    private List<ArticleVo> copyList(List<Article> records,boolean isAuthor,boolean isBody,boolean isTags) {
        List<ArticleVo> articleVoList = new ArrayList<>();
        for (Article article : records) {
            ArticleVo articleVo = copy(article,isAuthor,isBody,isTags);
            articleVoList.add(articleVo);
        }
        return articleVoList;
    }
}
